package com.likui.boot.util;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.data.jpa.domain.Specification;

import com.likui.boot.common.repository.DataSourceRequest;
import com.likui.boot.common.repository.Filters;

public class SpecificationUtil {
	public static <T> Specification<T> buildSpecification(final DataSourceRequest dsr) {
		return new Specification<T>() {
			@Override
			public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> predicates = new ArrayList<Predicate>();
				if (dsr.getFilter() != null) {
					List<Filters> filters = dsr.getFilter().getFilters();
					for (Filters f : filters) {
						// Operator:Contains\Doesnotcontain\endswith\eq\neq\startswith
						switch (f.getOperator()) {
						case LIKE:
							predicates.add(cb.like(root.get(f.getField()).as(String.class), "%" + f.getValue() + "%"));
							break;
						case UN_LIKE:
							predicates
									.add(cb.notLike(root.get(f.getField()).as(String.class), "%" + f.getValue() + "%"));
							break;
						case EQ:
							predicates.add(cb.equal(root.get(f.getField()).as(f.getValue().getClass()), f.getValue()));
							break;
						case NE:
							predicates
									.add(cb.notEqual(root.get(f.getField()).as(f.getValue().getClass()), f.getValue()));
							break;
						case L_LIKE:
							predicates.add(cb.like(root.get(f.getField()).as(String.class), "%" + f.getValue()));
							break;
						case R_LIKE:
							predicates.add(cb.like(root.get(f.getField()).as(String.class), f.getValue() + "%"));
							break;
						case GT:
							predicates.add(
									cb.greaterThan(root.get(f.getField()).as(f.getValue().getClass()), f.getValue()));
							break;
						case LT:
							predicates
									.add(cb.lessThan(root.get(f.getField()).as(f.getValue().getClass()), f.getValue()));
							break;
						case GTE:
							predicates.add(cb.greaterThanOrEqualTo(root.get(f.getField()).as(f.getValue().getClass()),
									f.getValue()));
							break;
						case GTENULL:
							Predicate gtenullOrClause = cb.or(
									cb.greaterThanOrEqualTo(root.get(f.getField()).as(f.getValue().getClass()),
											f.getValue()),
									cb.isNull(root.get(f.getField()).as(f.getValue().getClass())));
							predicates.add(gtenullOrClause);
							break;
						case LTE:
							predicates.add(cb.lessThanOrEqualTo(root.get(f.getField()).as(f.getValue().getClass()),
									f.getValue()));
							break;
						case LTENULL:
							Predicate ltenullOrClause = cb.or(
									cb.lessThanOrEqualTo(root.get(f.getField()).as(f.getValue().getClass()),
											f.getValue()),
									cb.isNull(root.get(f.getField()).as(f.getValue().getClass())));
							predicates.add(ltenullOrClause);
							break;

						}
					}
					// 将所有条件用 and 联合起来
					if (!predicates.isEmpty()) {
						return cb.and(predicates.toArray(new Predicate[predicates.size()]));
					}
				}
				return cb.conjunction();
			}
		};
	}
}